//
// Created by ziya on 2021/11/2.
//

#include "hpp/ObjectMonitor.h"
#include "hpp/Atomic.h"
#include "../include/common.h"
#include "hpp/ParkEvent.h"


void ObjectMonitor::enter(JavaThread *javaThread) {

    //cas 抢锁
    if(NULL == Atomic::cmpxchg_ptr(javaThread, &_owner, NULL) ){

        INFO_PRINT("抢到锁 %s \n",javaThread->_name.c_str());

        return;

    }

    if(javaThread == _owner){
        _recursions++;

        INFO_PRINT("重入 %s \n",javaThread->_name.c_str());

        return;
    }

    AddTask(new ObjectWaiter(javaThread));

    javaThread->parkEvent->park();

}

void ObjectMonitor::exit(JavaThread *javaThread) {

    if(javaThread == _owner && _recursions == 0){
        _recursions--;

        INFO_PRINT("处理重入 %s \n",javaThread->_name.c_str());

        return;
    }

    INFO_PRINT("释放锁 %s \n",javaThread->_name.c_str());

    _owner = NULL;


    //出对
    ObjectWaiter *objectWaiter = DequeueTask();

    //唤醒
    objectWaiter->_thread->parkEvent->unPark();
}

void ObjectMonitor::AddTask(ObjectWaiter* node){
    assert(node != NULL, "should not dequeue NULL node");
    assert(node->_prev == NULL, "node already in list");
    assert(node->_next == NULL, "node already in list");
    INFO_PRINT("阻塞，加入队列 %s \n",node->_thread->_name.c_str());
    if (_cxq == NULL) {
        _cxq = node;
        node->_prev = node;
        node->_next = node;
    } else {
        ObjectWaiter* head = _cxq ;
        ObjectWaiter* tail = head->_prev;
        assert(tail->_next == head, "invariant check");
        tail->_next = node;
        head->_prev = node;
        node->_next = head;
        node->_prev = tail;
    }
}

ObjectWaiter* ObjectMonitor::DequeueTask() {
    ObjectWaiter* node = _cxq;
    if (node) {
        DequeueSpecificTask(node);
    }
    return node;
}


void ObjectMonitor::DequeueSpecificTask(ObjectWaiter *node) {
    assert(node != NULL, "should not dequeue NULL node");
    assert(node->_prev != NULL, "node already removed from list");
    assert(node->_next != NULL, "node already removed from list");

    ObjectWaiter* next = node->_next;
    if (next == node) {
        assert(node->_prev == node, "invariant check");
        _cxq= NULL;
    } else {
        ObjectWaiter* prev = node->_prev;
        assert(prev->_next == node, "invariant check");
        assert(next->_prev == node, "invariant check");
        next->_prev = prev;
        prev->_next = next;
        if (_cxq == node) {
            _cxq = next;
        }
    }
    node->_next = NULL;
    node->_prev = NULL;
}

